package at.markushi.ui;

import at.markushi.ui.util.UiHelper;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.element.ShapeElement;
import ohos.app.Context;

import static ohos.agp.components.element.ShapeElement.OVAL;


public class RevealColorView extends ComponentContainer implements Component.EstimateSizeListener, ComponentContainer.ArrangeListener{

	public static final int ANIMATION_REVEAL = 0;
	public static final int ANIMATION_HIDE = 2;
	private static final float SCALE = 8f;
	private Component inkView;
	private RgbColor inkColor;
	private ShapeElement circle;
	private AnimatorProperty animator;

	public RevealColorView(Context context) {
		this(context, null);
	}

	public RevealColorView(Context context, AttrSet attrSet) {
		this(context, attrSet, "");
	}

	public RevealColorView(Context context, AttrSet attrSet, String styleName) {
		super(context, attrSet, styleName);

		inkView = new Component(context);
		addComponent(inkView);
		circle = new ShapeElement();
		circle.setShape(OVAL);
		UiHelper.setBackground(inkView, circle);
		inkView.setVisibility(Component.INVISIBLE);
		setArrangeListener(this);
		setEstimateSizeListener(this);

	}

	@Override
	public boolean onArrange(int l, int t, int r, int b) {
		inkView.arrange(l, t, l + inkView.getEstimatedWidth(), t + inkView.getEstimatedHeight());
		return true;
	}

	@Override
	public boolean onEstimateSize(int i, int i1) {
		final int width = Component.MeasureSpec.getSize(i);
		final int height = Component.MeasureSpec.getSize(i1);
		setEstimatedSize(width, height);

		final float circleSize = (float) Math.sqrt(width * width + height * height) * 2f;
		final int size = (int) (circleSize / SCALE);
		final int sizeSpec = Component.MeasureSpec.getMeasureSpec(size, Component.MeasureSpec.PRECISE);
		inkView.estimateSize(sizeSpec, sizeSpec);
		return true;
	}

	/**
	 * 显示圆形动画
	 *
	 * @param x 点击的x轴坐标
	 * @param y 点击的y轴坐标
	 * @param color 设置的动画颜色
	 * @param listener 动画状态变化监听
	 */
	public void reveal(final int x, final int y, final RgbColor color, Animator.StateChangedListener listener) {
		final int duration = 1000;
		reveal(x, y, color, 0, duration, listener);
	}

	/**
	 * 显示圆形动画
	 *
	 * @param x 点击的x轴坐标
	 * @param y 点击的y轴坐标
	 * @param color 设置的动画颜色
	 * @param startRadius 动画圆开始半径
	 * @param duration  动画时长
	 * @param listener 动画状态变化监听
	 */
	public void reveal(final int x, final int y, final RgbColor color, final int startRadius, long duration, final Animator.StateChangedListener listener) {
		if (color == inkColor) {
			return;
		}
		inkColor = color;

		if (animator != null) {
			animator.cancel();
		}

		circle.setRgbColor(color);
		inkView.setVisibility(Component.VISIBLE);

		final float startScale = startRadius * 2f / inkView.getHeight();
		final float finalScale = calculateScale(x, y) * SCALE;

		prepareView(inkView, x, y, startScale);

		animator = inkView.createAnimatorProperty();
		// 设置变化属性，可链式调用。
		animator.scaleX(finalScale).scaleY(finalScale).setDuration(duration).setStateChangedListener(new Animator.StateChangedListener() {
			@Override
			public void onStart(Animator animator) {
				if (listener != null) {
					listener.onStart(animator);
				}
			}

			@Override
			public void onStop(Animator animator) {
				if (listener != null) {
					listener.onStop(animator);
				}
			}

			@Override
			public void onCancel(Animator animator) {
				if (listener != null) {
					listener.onCancel(animator);
				}
			}

			@Override
			public void onEnd(Animator animator) {
				ShapeElement element = new ShapeElement();
				element.setRgbColor(color);
				setBackground(element);
				inkView.setVisibility(Component.INVISIBLE);
				if (listener != null) {
					listener.onEnd(animator);
				}
			}

			@Override
			public void onPause(Animator animator) {
				if (listener != null) {
					listener.onPause(animator);
				}
			}

			@Override
			public void onResume(Animator animator) {
				if (listener != null) {
					listener.onResume(animator);
				}
			}
		});

		prepareAnimator(animator, ANIMATION_REVEAL);
		// 启动动画或对动画做其他操作。
		animator.start();
	}

	/**
	 * 隐藏圆形动画
	 *
	 * @param x
	 * @param y
	 * @param color 设置的动画颜色
	 * @param listener
	 */
	public void hide(final int x, final int y, final RgbColor color, final Animator.StateChangedListener listener) {
		final int duration = 1000;
		hide(x, y, color, 0, duration, listener);
	}

	/**
	 * 隐藏圆形动画
	 *
	 * @param x 点击的x轴坐标
	 * @param y 点击的y轴坐标
	 * @param color 设置的动画颜色
	 * @param endRadius 动画结束时圆半径
	 * @param duration 动画时长
	 * @param listener 动画状态变化监听
	 */
	public void hide(final int x, final int y, final RgbColor color, final int endRadius, final long duration, final Animator.StateChangedListener listener) {
		inkColor = new RgbColor(255, 255, 255);
		if (animator != null) {
			animator.cancel();
		}
		inkView.setVisibility(Component.VISIBLE);

		ShapeElement element = new ShapeElement();
		element.setRgbColor(color);
		setBackground(element);
		final float startScale = calculateScale(x, y) * SCALE;
		final float finalScale = endRadius * SCALE / inkView.getWidth();

		prepareView(inkView, x, y, startScale);

		animator = inkView.createAnimatorProperty();
		// 设置变化属性，可链式调用。
		animator.scaleX(finalScale).scaleX(finalScale).setDuration(duration).setStateChangedListener(new Animator.StateChangedListener() {
			@Override
			public void onStart(Animator animator) {
				if (listener != null) {
					listener.onStart(animator);
				}
			}

			@Override
			public void onStop(Animator animator) {
				if (listener != null) {
					listener.onStop(animator);
				}
			}

			@Override
			public void onCancel(Animator animator) {
				if (listener != null) {
					listener.onCancel(animator);
				}
			}

			@Override
			public void onEnd(Animator animator) {
				inkView.setVisibility(Component.INVISIBLE);
				if (listener != null) {
					listener.onEnd(animator);
				}
			}

			@Override
			public void onPause(Animator animator) {
				if (listener != null) {
					listener.onPause(animator);
				}
			}

			@Override
			public void onResume(Animator animator) {
				if (listener != null) {
					listener.onResume(animator);
				}
			}
		});
		prepareAnimator(animator, ANIMATION_HIDE);
		animator.start();
	}

	public AnimatorProperty prepareAnimator(AnimatorProperty animator, int type) {
		animator.setCurveType(type);
		return animator;
	}

	private void prepareView(Component view, int x, int y, float scale) {
		final int centerX = (view.getWidth() / 2);
		final int centerY = (view.getHeight() / 2);
		view.setTranslationX(x - centerX);
		view.setTranslationY(y - centerY);
		view.setPivotX(centerX);
		view.setPivotY(centerY);
		view.setScaleX(scale);
		view.setScaleY(scale);
	}

	/**
	 * calculates the required scale of the ink-view to fill the whole view
	 *
	 * @param x circle center x
	 * @param y circle center y
	 * @return scale
	 */
	private float calculateScale(int x, int y) {
		final float centerX = getWidth() / 2f;
		final float centerY = getHeight() / 2f;
		final float maxDistance = (float) Math.sqrt(centerX * centerX + centerY * centerY);

		final float deltaX = centerX - x;
		final float deltaY = centerY - y;
		final float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
		final float scale = 0.5f + (distance / maxDistance) * 0.5f;
		return scale;
	}
}